#include "bsp_lcd.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"
#include "stdio.h"

struct tftlcd_t tftlcd_dev;

/* 初始化LCD ID */
void lcd_init(void)
{

    unsigned short lcdid = 0;
    lcdid = lcd_read_panelid();
    printf("屏幕ID为 %x \r\n", lcdid); /* 打印屏幕ID */

    lcdgpio_init(); /* 初始化屏幕 IO */
    lcd_reset();    /* 复位lcd */
    delay_ms(10);
    lcd_noreset(); /* 停止复位 */

    /* 根据不同的屏幕id设置屏幕参数 */
    if (LCD_7016 == lcdid)
    {
        tftlcd_dev.height = 600;
        tftlcd_dev.width = 1024;
        tftlcd_dev.pixsize = 4;
        tftlcd_dev.vspw = 3;
        tftlcd_dev.vbpd = 20;
        tftlcd_dev.vfpd = 12;
        tftlcd_dev.hspw = 20;
        tftlcd_dev.hbpd = 140;
        tftlcd_dev.hfpd = 160;
        tftlcd_dev.framebuffer = LCD_FRAME_ADDR;
        tftlcd_dev.forecolor = LCD_BLACK;
        tftlcd_dev.backcolor = LCD_WHITE;
        /* 设置lcd时钟为 51.2 M */
        lcd_clk(32, 3, 5);
    }

    /* 配置lcd 控制器接口 */
    LCDIF->CTRL = 0;
    LCDIF->CTRL |= (0 << 1) | (1 << 5) | (3 << 8) | (3 << 10) | (0 << 12) | (0 << 14) | (1 << 17) | (1 << 19);
    LCDIF->CTRL1 = 0;
    LCDIF->CTRL1 |= (7 << 16);
    LCDIF->TRANSFER_COUNT = 0;
    LCDIF->TRANSFER_COUNT = (tftlcd_dev.height << 16) | (tftlcd_dev.width << 0);
    LCDIF->VDCTRL0 = 0;
    LCDIF->VDCTRL0 = (tftlcd_dev.vspw << 0) | (1 << 20) | (1 << 21) | (1 << 24) | (0 << 25) | (0 << 26) | (0 << 27) | (1 << 28) | (0 << 29);
    LCDIF->VDCTRL1 = tftlcd_dev.vspw + tftlcd_dev.vbpd + tftlcd_dev.height + tftlcd_dev.vfpd;
    LCDIF->VDCTRL2 = (tftlcd_dev.hspw + tftlcd_dev.hbpd + tftlcd_dev.width + tftlcd_dev.hfpd) | (tftlcd_dev.hspw << 18);
    LCDIF->VDCTRL3 = (tftlcd_dev.vspw + tftlcd_dev.vbpd) | ((tftlcd_dev.hspw + tftlcd_dev.hbpd) << 16);
    LCDIF->VDCTRL4 = (tftlcd_dev.width) | (1 << 18);
    LCDIF->CUR_BUF = (unsigned int)(tftlcd_dev.framebuffer);
    LCDIF->NEXT_BUF = (unsigned int)(tftlcd_dev.framebuffer);

    lcd_enable(); /* 使能LCDIF控制接口 */
    delay_ms(10);
    lcd_clear(LCD_WHITE);
}

/* 像素时钟初始化 
 * lcd_clk = 24 * loopdiv / prediv / div
*/
void lcd_clk(unsigned char loopdiv, unsigned char prediv, unsigned char div)
{
    CCM_ANALOG->PLL_VIDEO_NUM = 0;
    CCM_ANALOG->PLL_VIDEO_DENOM = 0; /* pll5不使用小数分频器 */
    CCM_ANALOG->PLL_VIDEO = (1 << 13) | (2 << 19) | (loopdiv << 0);
    CCM_ANALOG->MISC2 &= ~(3 << 31);
    CCM_ANALOG->MISC2 = (0 << 31);
    CCM->CSCDR2 &= ~(7 << 15);
    CCM->CSCDR2 |= (2 << 15);
    CCM->CSCDR2 &= ~(7 << 12);
    CCM->CSCDR2 |= ((prediv - 1) << 12);
    CCM->CBCMR &= ~(7 << 23);
    CCM->CBCMR |= ((div - 1) << 23);
    CCM->CSCDR2 &= ~(7 << 9);
    CCM->CSCDR2 |= (0 << 9);
}

/* 使能lcd控制器 */
void lcd_enable(void)
{
    LCDIF->CTRL |= (1 << 0);
}

/* 复位lcd控制器 */
void lcd_reset(void)
{
    LCDIF->CTRL = 1 << 31;
}

/* 停止复位lcd控制器 */
void lcd_noreset(void)
{
    LCDIF->CTRL = 1 << 31;
}

/* 屏幕IO 初始化  */
void lcdgpio_init(void)
{
    gpio_pin_config_t bl_config;

    /* 配置IO复用 */
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0);

    IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0);
    IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0);

    /* 设置电气属性 */
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0X10B9);

    IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0X10B9);
    IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0X10B9);

    /* 设置背光 */
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0X10B0);
    /* 背光IO 初始化 */
    bl_config.direction = kGPIO_DigitalOutput;
    bl_config.outputLogic = 1;
    gpio_init(GPIO1, 8, &bl_config);
}

/* 读取屏幕ID */
unsigned short lcd_read_panelid(void)
{
    unsigned short idx = 0;

    /* 打开模拟开关 设置LCD_VSYNC为高电平，初始化GPIO*/
    /* IO复用为输出 */
    gpio_pin_config_t lcd_config;
    IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0); /* 复用为GPIO3_IO03 */
    IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0X10B0);

    /* GPIO初始化 */
    lcd_config.direction = kGPIO_DigitalOutput;
    lcd_config.outputLogic = 1;
    gpio_init(GPIO3, 3, &lcd_config);

    /* 读取屏幕ID ,IO复用为输出*/
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_GPIO3_IO12, 0); /* 复用为GPIO1_IO03 */
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_GPIO3_IO20, 0); /* 复用为GPIO1_IO03 */
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_GPIO3_IO28, 0); /* 复用为GPIO1_IO03 */
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_GPIO3_IO12, 0xF080);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_GPIO3_IO20, 0xF080);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_GPIO3_IO28, 0xF080);

    /* GPIO初始化 */
    lcd_config.direction = kGPIO_DigitalInput;
    gpio_init(GPIO3, 12, &lcd_config);
    gpio_init(GPIO3, 20, &lcd_config);
    gpio_init(GPIO3, 28, &lcd_config);

    /* 正式开始读取ID */
    idx |= (unsigned char)gpio_pinread(GPIO3, 28);
    idx |= (unsigned char)gpio_pinread(GPIO3, 20) << 1;
    idx |= (unsigned char)gpio_pinread(GPIO3, 13) << 2;

    if (idx == 2)
        return LCD_7016;
    else
        return 0;
}

/* 画点函数 */
inline void lcd_drawpoint(unsigned short x, unsigned short y, unsigned int color)
{
    x = 1024 - x;
    y = 600 - y;
    *(unsigned int *)((unsigned int)tftlcd_dev.framebuffer + tftlcd_dev.pixsize * (tftlcd_dev.width * y + x)) = color;
}

/* 读点函数 */
inline unsigned int lcd_readpoint(unsigned short x, unsigned short y)
{
    x = 1024 - x;
    y = 600 - y;
    return *(unsigned int *)((unsigned int)tftlcd_dev.framebuffer + tftlcd_dev.pixsize * (tftlcd_dev.width * y + x));
}

/* 清屏函数 */
void lcd_clear(unsigned int color)
{
    unsigned int num;
    unsigned int i = 0;
    unsigned int *startaddr = (unsigned int *)tftlcd_dev.framebuffer;
    num = (unsigned int)(tftlcd_dev.width * tftlcd_dev.height);
    for (i = 0; i < num; i++)
    {
        startaddr[i] = color;
    }
}

void lcd_fill(unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1, unsigned int color)
{
    unsigned short x, y;

    x0 = 1024 - x0;
    x1 = 1024 - x1;
    y0 = 600 - y0;
    y1 = 600 - y1;

    if (x0 < 0)
        x0 = 0;
    if (y0 < 0)
        y0 = 0;
    if (x1 >= tftlcd_dev.width)
        x1 = tftlcd_dev.width - 1;
    if (y1 >= tftlcd_dev.height)
        y1 = tftlcd_dev.height - 1;

    for (y = y0; y <= y1; y++)
    {
        for (x = x0; x <= x1; x++)
            lcd_drawpoint(x, y, color);
    }
}
